package cn.xinfei.xdecision.engine.runner.executor.strategy.component;

import cn.xinfei.xdecision.common.model.component.ComponentVo;
import cn.xinfei.xdecision.common.model.component.decisiontree.DecisionTreeDetail;
import cn.xinfei.xdecision.common.model.component.decisiontree.vo.DecisionTreeVersionVo;
import cn.xinfei.xdecision.common.model.component.decisiontree.vo.DecisionTreeVo;
import cn.xinfei.xdecision.common.model.component.strategyout.StrategyOutput;
import cn.xinfei.xdecision.common.model.datax.datamanage.Field;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeDetailService;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeService;
import cn.xinfei.xdecision.common.service.component.decisiontree.DecisionTreeVersionService;
import cn.xinfei.xdecision.common.service.component.strategyout.StrategyOutputService;
import cn.xinfei.xdecision.common.service.datax.datamanage.FieldService;
import cn.xinfei.xdecision.common.utils.enums.enginex.ComponentTypeEnum;
import cn.xinfei.xdecision.common.utils.enums.enginex.ConditionValueTypeEnum;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.constant.EngineResultEnum;
import cn.xinfei.xdecision.engine.runner.context.XDecisionContext;
import cn.xinfei.xdecision.engine.runner.executor.ComponentHandler;
import cn.xinfei.xdecision.engine.runner.executor.XRunner;
import cn.xinfei.xdecision.engine.runner.executor.handler.DecisionTreeNodeHandler;
import cn.xinfei.xdecision.engine.runner.executor.model.StateTransmitModel;
import cn.xinfei.xdecision.engine.runner.executor.strategy.EngineComponentRunner;
import cn.xinfei.xdecision.engine.runner.metadata.MetadataProvider;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@XRunner
@Slf4j
@Service
public class DecisionTreeComponent extends EngineComponentRunner {

    @Autowired
    private FieldService fieldService;

    @Autowired
    protected MetadataProvider metadataProvider;

    @Autowired
    protected StrategyOutputService strategyOutputService;

    @Autowired
    private DecisionTreeService decisionTreeService;

    @Autowired
    private DecisionTreeDetailService decisionTreeDetailService;

    @Autowired
    private DecisionTreeNodeHandler decisionTreeNodeHandler;

    @Autowired
    private DecisionTreeVersionService decisionTreeVersionService;

    @Override
    public String getServiceName() {
        return EngineComponentRunner.PRE + ComponentTypeEnum.DECISION_TREE.getType();
    }

    @Override
    public void before(ComponentHandler nodeHandler) {
        String componentCode = nodeHandler.getCode();
        ComponentVo componentVo = nodeHandler.getComponentVo();
        Long versionNo = componentVo.getVersionNo();
        DecisionTreeVo decisionTreeVo = decisionTreeService.queryExecuteDecisionTreeByVersionNo(componentCode, versionNo);
        DecisionTreeVersionVo executeVersion = decisionTreeVo.getExecuteVersion();
        Long versionId = executeVersion.getId();
        componentVo.setVersionId(versionId);
    }

    @Override
    public Map<String, StrategyOutput> getOutputFieldInfo(ComponentHandler nodeHandler) {
        Map<String, StrategyOutput> strategyOutputMap = super.getOutputFieldInfo(nodeHandler);
        String componentCode = nodeHandler.getCode();
        try {
            ComponentVo componentVo = nodeHandler.getComponentVo();
            Long versionNo = componentVo.getVersionNo();
                Map<String, FieldInfoVo> fieldInfo = metadataProvider.getFieldInfo();
                List<DecisionTreeVersionVo> decisionTreeVersionVos = decisionTreeVersionService.queryVersionByTreeCodes(componentCode, versionNo);
                for (DecisionTreeVersionVo decisionTreeVersionVo : decisionTreeVersionVos) {
                    String resultFieldCode = decisionTreeVersionVo.getResultFieldCode();
                    FieldInfoVo fieldInfoVo = fieldInfo.get(resultFieldCode);
                    StrategyOutput output = new StrategyOutput();
                    output.setFieldCode(resultFieldCode);
                    output.setFieldValue(decisionTreeVersionVo.getDefaultValue());
                    output.setVarValueType(fieldInfoVo.getValueType());
                    output.setValueType(ConditionValueTypeEnum.VARIABLE.getCode());
                    output.setStage(fieldInfoVo.getStage());
                    output.setFixed(true);
                    strategyOutputMap.put(resultFieldCode, output);
                }
        } catch (Exception e) {
            log.error("DecisionTablesNode,getNodeField:获取决策树指标异常,engineNode={},error={}", componentCode, e.getMessage(), e);
        }
        return strategyOutputMap;
    }

    @Override
    public void getNodeFieldValue(Set<String> fieldSet, String nodeCode) throws Exception {

    }

    @Override
    public Map<String, FieldInfoVo> getInputFieldInfo(ComponentHandler nodeHandler) {

        Map<String, FieldInfoVo> fieldVos = new HashMap<>();
        Set<String> fieldCodes = new HashSet<>();
        String componentCode = nodeHandler.getCode();
        try {
            ComponentVo componentVo = nodeHandler.getComponentVo();
            Map<String, FieldInfoVo> fieldInfo = metadataProvider.getFieldInfo();

            Long versionId = componentVo.getVersionId();
            List<DecisionTreeDetail> detailVos = decisionTreeDetailService.queryByVersionId(versionId);
            extractField(detailVos, fieldCodes);
            List<Field> fields = fieldService.queryByEns(fieldCodes);
            fields.forEach(field -> {
                String fieldCode = field.getFieldCode();
                FieldInfoVo value = fieldInfo.get(fieldCode);
                if (value != null) {
                    fieldVos.put(fieldCode, value);
                }
            });
        } catch (Exception e) {
            log.error("DecisionTablesNode,getNodeField:获取决策树指标异常,componentCode={},error={}", componentCode, e.getMessage(), e);
        }
        return fieldVos;
    }

    private void extractField(List<DecisionTreeDetail> details, Set<String> fieldCodes) {
        if (details != null && details.size() > 0) {
            for (int i = 0; i < details.size(); i++) {
                DecisionTreeDetail decisionTreeDetail = details.get(i);
                String fieldCode = decisionTreeDetail.getFieldCode();
                fieldCodes.add(fieldCode);
                List<DecisionTreeDetail> children = decisionTreeDetail.getChildren();
                extractField(children, fieldCodes);
            }
        }
        return;
    }

    @Override
    public StateTransmitModel runNode(ComponentHandler nodeHandler) throws EvaluationException {

        String componentCode = nodeHandler.getComponentCode();
        ComponentVo componentVo = nodeHandler.getComponentVo();
        Long versionId = componentVo.getVersionId();
        DecisionTreeVo decisionTreeVo = decisionTreeService.queryExecuteDecisionTree(componentCode, versionId);
        DecisionTreeVersionVo version = decisionTreeVo.getExecuteVersion();
        String resultFieldEn = version.getResultFieldCode();
        //执行决策表
        Object executeResult = decisionTreeNodeHandler.executeDecisionTree(version);

        log.info("决策树执行结果，componentCode={},{}={}", componentCode, resultFieldEn, executeResult);

        setOutput(nodeHandler, resultFieldEn, executeResult);

        if (null != executeResult) {
//                log.info("决策树执行结果，executeResult={}",executeResult);
            setOutput(nodeHandler, resultFieldEn, executeResult);
        } else {
            //未命中输出，默认值
            setOutput(nodeHandler, resultFieldEn, version.getDefaultValue());
        }
        return XDecisionContext.getContext().getStateContext().setEngineResultEnum(EngineResultEnum.SUCCESS_END);
    }


}
